#include <stdio.h>
 
int main(int argc,const char * argv[])
{
 //⼆维数组的初始化
 int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
 //⼆维数组的数组名 是⼀个⾏指针
 printf("arr = %p\n",arr);
 printf("arr + 1 = %p\n",arr + 1);
 printf("arr + 2 = %p\n",arr + 2);
 //每次加1 相当于偏移⼀⾏ <====> 1* 列数 * 数据类型
 //通过地址的⽅式 取 第⼆⾏ ，第3列的数据
 //arr[1][2]
 printf("%d\n",*(*(arr+1)+2));
 //对⼆维数组名 使⽤ * 相当于 给指针 进⾏降维 成⼀级指针
 //降维之后，地址偏移 每次偏移 偏移⼀个数据类型
 //再⼀次使⽤ * 相当于取出对应的数据
 //⼆维数组的遍历
 //arr[i][j] <===> *(arr[i] + j) <===> *(*(arr + i) + j)
 int i,j;
 for(i = 0;i < 3; i++)
 {
 for(j = 0; j < 4 ; j++)
 {
 //printf("%02d ",arr[i][j]);
 //printf("%02d ",*(arr[i] + j));
 printf("%02d ",*(*(arr + i) + j));
 }
 putchar(10);
 }
 //注意：
 //⼆维数组名 也是⼀个地址常量 不能赋值 arr++;//error
 //使⽤*p去保存 ⼆维数组的名字
 int *p = arr;
 printf("p = %p\n",p);
 printf("*p = %d\n",*p);
 printf("*(p + 1) = %d\n",*(p + 1));
 //⼆维数组的名字 是⼀个⾏指针 每次偏移⼀整⾏
 //已经操过基本的数据类型
 //不能使⽤普通的⼀级指针 去保存⼆维数组的地址
 //保存 是ok 没问题，但是，在偏移的时候不会和⼆维数组⼀样 偏移⼀样
 //当 p + 1,操作系统会认为 你是想偏移⼀⾏
 //但是， p 是 int * 类型 只能偏移 4个字节 ，就会有冲突，就会报警告
 //⼆维数组 数组名 是可以 **arr ⽽指针p 不能**p;
 puts("****************************");
 printf("arr[0][0] = %d\n",**arr);
 //printf("arr[0][0] = %d\n",**p);//会有问题
 return 0;
}
